﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Lime49;

namespace LockCrypt.Core {
    /// <summary>
    /// An account template
    /// </summary>
    public class TemplateBase : ITemplate {
        public virtual string ID { get; set; }
        public virtual string Name { get; set; }
        public virtual bool ShowNotes { get; set; }
        public virtual IList<IField> Fields { get; set; }
        public virtual bool CanUserEdit { get; set; }

        public TemplateBase() {
            CanUserEdit = true;
            ID = Utils.GenID(true);
            ShowNotes = true;
            Fields = new List<IField>();
        }

        /// <summary>
        /// Converts this template to an XElement.
        /// </summary>
        /// <returns>An XElement representing this template.</returns>
        public XElement ToXElement() {
            XElement xFields = new XElement("fields");
            foreach(IField field in Fields) {
                try {
                    xFields.Add(field.ToXElement());
                } catch(Exception ex) {
                    Console.WriteLine("Error exporting field: {0}", ex.Message);
                }
            }
            XElement xTemplate = new XElement("template",
                new XElement("title", HtmlUtils.HtmlEncode(this.Name)),
                new XAttribute("canuseredit", this.CanUserEdit.ToString()),
                new XAttribute("id", HtmlUtils.HtmlEncode(this.ID)),
                new XAttribute("shownotes", this.ShowNotes.ToString()),
                xFields);
            return xTemplate;
        }

        /// <summary>
        /// Initializes a new <see cref="TemplateBase"/> from an XElement.
        /// </summary>s
        /// <param name="element">The XElement containing the template data.</param>
        /// <returns>The template contained in the specified XElement.</returns>
        public static ITemplate FromXElement(XElement element) {
            try {
                ITemplate template = new TemplateBase() {
                    Name = HtmlUtils.HtmlDecode(element.Element("title").Value),
                    CanUserEdit = bool.Parse(element.Attribute("canuseredit").Value),
                    ID = HtmlUtils.HtmlDecode(element.Attribute("id").Value),
                    ShowNotes = bool.Parse(element.Attribute("shownotes").Value)
                };
                foreach(XElement field in (element.Element("fields") ?? new XElement("fields")).Elements("field")) {
                    try {
                        template.Fields.Add(FieldBase.FromXElement(field));
                    } catch {
                        Console.WriteLine("Invalid field in template '{0}'", template.Name); // log it but the rest of the template data may be valid
                    }
                }
                return template;
            } catch { // usually NullReferenceException, but if something's invalid the template will be invalid
                throw new Exception("Invalid template");
            }
        }

        /// <summary>
        /// Creates a deep copy of this template.
        /// </summary>
        /// <returns>A clone of this template.</returns>
        public virtual ITemplate Clone() {
            TemplateBase clone = new TemplateBase() {
                CanUserEdit = this.CanUserEdit,
                ID = this.ID,
                Name = this.Name,
                ShowNotes = this.ShowNotes
            };
            foreach(IField field in this.Fields) {
                clone.Fields.Add(field.Clone());
            }
            return clone;
        }

        public override string ToString() {
            return string.Format("{0} ({1} fields)", Name, Fields.Count);
        }
    }
}
